package com.gzj.environment.module.collectData.indicator.impl;

import cn.hutool.core.util.StrUtil;
import com.gzj.environment.enums.collectData.CollectDataTypeEnum;
import com.gzj.environment.framework.util.DateUtil;
import com.gzj.environment.model.collectData.dto.AirCollectData;
import com.gzj.environment.module.collectData.handler.InsertDataHandler;
import com.gzj.environment.module.collectData.indicator.IndicatorHandle;
import com.gzj.environment.module.collectData.util.ConvertUtils;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 空气站指标处理
 */
@Service
@Slf4j
public class AirIndicatorHandle implements IndicatorHandle {

    @Autowired
    private InsertDataHandler insertDataHandler;

    /**
     *  空气站暂存数据，格式为
     *  Map<ip, Map<第几条指标, 指标消息>>
     *  对于空气站来说，四条指标消息才会构成一次完整的数据采集，所以这个map存的是各空气站没有构成一次完整采集时的暂存指标消息
     */
    private static final Map<String, Map<String, String>> airMap = new ConcurrentHashMap<>();

    /**
     * 返回指标种类
     * @return
     */
    @Override
    public CollectDataTypeEnum indicatorType() {
        return CollectDataTypeEnum.AIR;
    }

    /**
     * 处理指标
     * @param group 点位组
     * @param number 点位编号
     * @param ctx 客户端信道信息
     * @param message 指标数据
     */
    @Override
    public void indicatorHandle(String group, String number, ChannelHandlerContext ctx, String message) {
        // 1.获取是第几条指标
        String count = message.substring(5, 6);

        // 2.获取信道的ip地址
        String ip = ctx.channel().remoteAddress().toString();

        // 3.从airMap中拉取ip对应的map信息
        // 3.1.如果map是null，那么先创建
        Map<String, String> indicatorMap = airMap.computeIfAbsent(ip, k -> new HashMap<>());
        // 3.2.判断是否有重复数据了（有设备故障的情况）
        if (indicatorMap.containsKey(count)) {
            // 处理数据
            doHandleAirCollectData(indicatorMap, group, number);
            // 清空原来ip对应的指标消息
            indicatorMap = new HashMap<>();
            // 将本次的count和message加入指标消息
            indicatorMap.put(count, message);
            // 将新的indicatorMap加入到airMap中
            airMap.put(ip, indicatorMap);
            return;
        }
        // 3.3.把新的信息加到指标消息中
        indicatorMap.put(count, message);
        // 如果加入新的信息后是一条完整的数据采集
        if (isFullData(indicatorMap)) {
            // 处理数据
            doHandleAirCollectData(indicatorMap, group, number);
            // 清空原来ip对应的指标消息
            indicatorMap = new HashMap<>();
            // 将新的indicatorMap加入到airMap中
            airMap.put(ip, indicatorMap);
        }
    }

    /**
     * 判断是否是一次完整的采集
     * @param indicatorMap 指标信息对应的map
     * @return
     */
    private boolean isFullData(Map<String, String> indicatorMap) {
        return indicatorMap.containsKey("1")
                && indicatorMap.containsKey("2")
                && indicatorMap.containsKey("3")
                && indicatorMap.containsKey("4");
    }

    /**
     * 处理指标消息，将其封装为AirCondition，并将信息的信息放到新增队列中去
     * @param indicatorMap 指标消息
     * @param group 本采集消息对应哪个点位组
     * @param number 点位编号
     */
    private void doHandleAirCollectData(Map<String, String> indicatorMap, String group, String number) {
        log.info("----->开始解析指标，并将结果保存到数据库中。当前的采集数据为：{}", indicatorMap.keySet());
        String indicator1 = indicatorMap.get("1");
        String indicator2 = indicatorMap.get("2");
        String indicator3 = indicatorMap.get("3");
        String indicator4 = indicatorMap.get("4");

        AirCollectData airCollectData = new AirCollectData(group, number);
        if (StrUtil.isNotBlank(indicator1)) {
            String data = getIndicatorData(indicator1);
            fillAirCollectDataByFirstIndicator(airCollectData, data);
        }
        if (StrUtil.isNotBlank(indicator2)) {
            String data = getIndicatorData(indicator2);
            fillAirCollectDataBySecondIndicator(airCollectData, data);
        }
        if (StrUtil.isNotBlank(indicator3)) {
            String data = getIndicatorData(indicator3);
            fillAirCollectDataByThirdIndicator(airCollectData, data);
        }
        if (StrUtil.isNotBlank(indicator4)) {
            String data = getIndicatorData(indicator4);
            fillAirCollectDataByFourthIndicator(airCollectData, data);
        }

        InsertDataHandler.InsertTask insertTask = new InsertDataHandler.InsertTask(CollectDataTypeEnum.AIR, airCollectData);
        insertDataHandler.addTask(insertTask);

    }

    /**
     * 获取指标中的数据
     * @param command 指标
     * @return
     */
    private String getIndicatorData(String command) {
        // 获取从第几位开始读
        String startHex = command.substring(6, 8);
        int start = ConvertUtils.hexToDec(startHex);
        // 获取读几位
        String lengthHex = command.substring(8, 10);
        int length = ConvertUtils.hexToDec(lengthHex);
        // 获取数据
        return command.substring((start - 1) * 2, (start + length - 1) * 2);
    }

    /**
     * 将第一条指标中的信息填充到采集实体中
     * @param airCollectData 采集实体
     * @param data 指标数据
     */
    private void fillAirCollectDataByFirstIndicator(AirCollectData airCollectData, String data) {
        // 获取pm2.5
        String pm25Hex = data.substring(0, 4);
        int pm25 = ConvertUtils.hexToDec(pm25Hex);

        // 获取pm10
        String pm10Hex = data.substring(4, 8);
        int pm10 = ConvertUtils.hexToDec(pm10Hex);

        // 获取tsp
        String tspHex = data.substring(8, 12);
        int tsp = ConvertUtils.hexToDec(tspHex);

        airCollectData.setPm25(String.valueOf(pm25));
        airCollectData.setPm10(String.valueOf(pm10));
        airCollectData.setTsp(String.valueOf(tsp));

    }

    /**
     * 将第二条指标中的信息填充到采集实体中
     * @param airCollectData 采集实体
     * @param data 指标数据
     */
    private void fillAirCollectDataBySecondIndicator(AirCollectData airCollectData, String data) {
        // 获取湿度
        String humidityHex = data.substring(0, 4);
        double humidity = (double) ConvertUtils.hexToDec(humidityHex) / 10;
        humidity = new BigDecimal(humidity).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();

        // 获取温度
        String temperatureHex = data.substring(4, 8);
        double temperature = (double) ConvertUtils.hexToDec(temperatureHex) / 10;
        temperature = new BigDecimal(temperature).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();

        // 获取噪声
        String noiseHex = data.substring(8, 12);
        double noise = (double) ConvertUtils.hexToDec(noiseHex) / 10;
        noise = new BigDecimal(noise).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();

        // 获取气压
        String airPressureHex = data.substring(20, 24);
        double airPressure = (double) ConvertUtils.hexToDec(airPressureHex) / 10;
        airPressure = new BigDecimal(airPressure).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();

        airCollectData.setHumidity(String.valueOf(humidity));
        airCollectData.setTemperature(String.valueOf(temperature));
        airCollectData.setNoise(String.valueOf(noise));
        airCollectData.setAirPressure(String.valueOf(airPressure));
    }

    /**
     * 将第三条指标中的信息填充到采集实体中
     * @param airCollectData 采集实体
     * @param data 指标数据
     */
    private void fillAirCollectDataByThirdIndicator(AirCollectData airCollectData, String data) {
        // 获取风速
        double windSpeed = (double) ConvertUtils.hexToDec(data) / 10;
        windSpeed = new BigDecimal(windSpeed).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();

        airCollectData.setWindSpeed(String.valueOf(windSpeed));
    }

    /**
     * 将第四条指标中的信息填充到采集实体中
     * @param airCollectData 采集实体
     * @param data 指标数据
     */
    private void fillAirCollectDataByFourthIndicator(AirCollectData airCollectData, String data) {
        // 获取风向数值
        int wind = ConvertUtils.hexToDec(data);
        // 根据数值获取风向
        String windDirection = getDirectionByWindData(wind);

        airCollectData.setWindDirection(windDirection);
    }

    /**
     * 根据风向数值获取风向
     * @param wind 风向数值
     * @return
     */
    private String getDirectionByWindData(Integer wind) {
        if (wind >= 23 && wind < 68) {
            return "东北风";
        }
        if (wind >= 68 && wind < 113) {
            return "东风";
        }
        if (wind >= 113 && wind < 158) {
            return "东南风";
        }
        if (wind >= 158 && wind < 203) {
            return "南风";
        }
        if (wind >= 203 && wind < 248) {
            return "西南风";
        }
        if (wind >= 248 && wind < 293) {
            return "西风";
        }
        if (wind >= 293 && wind < 338) {
            return "西北风";
        }
        return "北风";
    }
}
